-
โ
โ
ReactDOM.render(<h1>Hello, world!</h1>,document.getElementById('root'));
It displays a heading saying "Hello, world!" on the page.
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/wveBJBMโ
Click the link above to open an online editor. Feel free to make some changes, and see how they affect the output. Most pages in this guide will have editable examples like this one.
In this guide, we will examine the building blocks of React apps: elements and components. Once you master them, you can create complex apps from small reusable pieces.
TipThis guide is designed for people who prefer learning concepts step by step. If you prefer to learn by doing, check out our practical tutorial. You might find this guide and the tutorial complementary to each other.
This is the first chapter in a step-by-step guide about main React concepts. You can find a list of all its chapters in the navigation sidebar. If you're reading this from a mobile device, you can access the navigation by pressing the button in the bottom right corner of your screen.
Every chapter in this guide builds on the knowledge introduced in earlier chapters. You can learn most of React by reading the "Main Concepts" guide chapters in the order they appear in the sidebar. For example, "Introducing JSX" is the next chapter after this one.
React is a JavaScript library, and so we'll assume you have a basic understanding of the JavaScript language. If you don't feel very confident, we recommend going through a JavaScript tutorial to check your knowledge level and enable you to follow along this guide without getting lost. It might take you between 30 minutes and an hour, but as a result you won't have to feel like you're learning both React and JavaScript at the same time.
NoteThis guide occasionally uses some newer JavaScript syntax in the examples. If you haven't worked with JavaScript in the last few years, these three points should get you most of the way.
const element = <h1>Hello, world!</h1>;
This funny tag syntax is neither a string nor HTML.
It is called JSX, and it is a syntax extension to JavaScript. We recommend using it with React to describe what the UI should look like. JSX may remind you of a template language, but it comes with the full power of JavaScript.
JSX produces React "elements". We will explore rendering them to the DOM in the next section. Below, you can find the basics of JSX necessary to get you started.
React embraces the fact that rendering logic is inherently coupled with other UI logic: how events are handled, how the state changes over time, and how the data is prepared for display.
Instead of artificially separating technologies by putting markup and logic in separate files, React separates concerns with loosely coupled units called "components" that contain both. We will come back to components in a further section, but if you're not yet comfortable putting markup in JS, this talk might convince you otherwise.
React doesn't require using JSX, but most people find it helpful as a visual aid when working with UI inside the JavaScript code. It also allows React to show more useful error and warning messages.
With that out of the way, let's get started!
In the example below, we declare a variable
called name
and then use it inside JSX by wrapping it in
curly braces:
const name = 'Josh Perez';const element = <h1>Hello, {name}</h1>;ReactDOM.render(element,document.getElementById('root'));
You can put any valid
JavaScript expression
inside the curly braces in JSX. For example, 2 + 2, user.firstName, or formatName(user)
are all valid JavaScript expressions.
In the example below, we embed the result
of calling a JavaScript function, formatName(user), into an <h1>
element.
function formatName(user) {return user.firstName + ' ' + user.lastName;}โconst user = {firstName: 'Harper',lastName: 'Perez'};โconst element = (<h1> Hello, {formatName(user)}! </h1>);โReactDOM.render(element,document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/oNwgZgmโ
We split JSX over multiple lines for readability. While it isn't required, when doing this, we also recommend wrapping it in parentheses to avoid the pitfalls of automatic semicolon insertion.
After compilation, JSX expressions become regular JavaScript function calls and evaluate to JavaScript objects.
This means that you can use JSX inside of if
statements and for
loops, assign it to variables, accept it as
arguments, and return it from
functions:
function getGreeting(user) {if (user) {return <h1>Hello, {formatName(user)}!</h1>; }return <h1>Hello, Stranger.</h1>;}
You may use quotes to specify string literals as attributes:
const element = <div tabIndex="0"></div>;
You may also use curly braces to embed a JavaScript expression in an attribute:
const element = <img src={user.avatarUrl}></img>;
Don't put quotes around curly braces when embedding a JavaScript expression in an attribute. You should either use quotes (for string values) or curly braces (for expressions), but not both in the same attribute.
Warning:Since JSX is closer to JavaScript than to HTML, React DOM uses camelCase property naming convention instead of HTML attribute names.For example, class becomes className in JSX, and tabindex becomes tabIndex.
If a tag is empty, you may close it
immediately with />, like XML:
const element = <img src={user.avatarUrl} />;
JSX tags may contain children:
const element = (<div><h1>Hello!</h1><h2>Good to see you here.</h2></div>);
It is safe to embed user input in JSX:
const title = response.potentiallyMaliciousInput;// This is safe:const element = <h1>{title}</h1>;
By default, React DOM escapes any values embedded in JSX before rendering them. Thus it ensures that you can never inject anything that's not explicitly written in your application. Everything is converted to a string before being rendered. This helps prevent XSS (cross-site-scripting) attacks.
Babel compiles JSX down to React.createElement()
calls.
These two examples are identical:
const element = (<h1 className="greeting">Hello, world!</h1>);
const element = React.createElement('h1',{className: 'greeting'},'Hello, world!');
React.createElement()
performs a few checks to help you write
bug-free code but essentially it creates an
object like this:
// Note: this structure is simplifiedconst element = {type: 'h1',props: {className: 'greeting',children: 'Hello, world!'}};
These objects are called "React elements". You can think of them as descriptions of what you want to see on the screen. React reads these objects and uses them to construct the DOM and keep it up to date.
We will explore rendering React elements to the DOM in the next section.
Tip:We recommend using the "Babel" language definition for your editor of choice so that both ES6 and JSX code is properly highlighted.
An element describes what you want to see on the screen:
const element = <h1>Hello,
world</h1>;
Unlike browser DOM elements, React elements are plain objects, and are cheap to create. React DOM takes care of updating the DOM to match the React elements.
Note:One might confuse elements with a more widely known concept of "components". We will introduce components in the next section. Elements are what components are "made of", and we encourage you to read this section before jumping ahead.
Let's say there is a <div>
somewhere in your HTML file:
<div id="root"></div>
We call this a "root" DOM node because everything inside it will be managed by React DOM.
Applications built with just React usually have a single root DOM node. If you are integrating React into an existing app, you may have as many isolated root DOM nodes as you like.
To render a React element into a root DOM
node, pass both to [ReactDOM.render()](<https://reactjs.org/docs/react-dom.html#render>):
const element = <h1>Hello, world</h1>;ReactDOM.render(element, document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/mdwyWeb?editors=0010โ
It displays "Hello, world" on the page.
React elements are immutable. Once you create an element, you can't change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
With our knowledge so far, the only way to
update the UI is to create a new element,
and pass it to [ReactDOM.render()](<https://reactjs.org/docs/react-dom.html#render>).
Consider this ticking clock example:
function tick() {const element = (<div> <h1>Hello, world!</h1> <h2>It is {new Date().toLocaleTimeString()}.</h2> </div>);ReactDOM.render(element, document.getElementById('root'));}โsetInterval(tick, 1000);
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/eYRmvNy?editors=0010โ
It calls [ReactDOM.render()](<https://reactjs.org/docs/react-dom.html#render>)
every second from a [setInterval()](<https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval>)
callback.
Note:In practice, most React apps only call ReactDOM.render() once. In the next sections we will learn how such code gets encapsulated into stateful components.We recommend that you don't skip topics because they build on each other.
React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.
You can verify by inspecting the last example with the browser tools:
Even though we create an element describing the whole UI tree on every tick, only the text node whose contents have changed gets updated by React DOM.
In our experience, thinking about how the UI should look at any given moment, rather than how to change it over time, eliminates a whole class of bugs.
Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen.
The simplest way to define a component is to write a JavaScript function:
function Welcome(props) {return <h1>Hello, {props.name}</h1>;}
This function is a valid React component because it accepts a single "props" (which stands for properties) object argument with data and returns a React element. We call such components "function components" because they are literally JavaScript functions.
You can also use an ES6 class to define a component:
class Welcome extends React.Component {render() {return <h1>Hello, {this.props.name}</h1>;}}
The above two components are equivalent from React's point of view.
Function and Class components both have some additional features that we will discuss in the next sections.
Previously, we only encountered React elements that represent DOM tags:
const element = <div />;
However, elements can also represent user-defined components:
const element = <Welcome name="Sara" />;
When React sees an element representing a user-defined component, it passes JSX attributes and children to this component as a single object. We call this object "props".
For example, this code renders "Hello, Sara" on the page:
function Welcome(props) { return <h1>Hello, {props.name}</h1>;}โconst element = <Welcome name="Sara" />;ReactDOM.render(element,document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/QWgwpjd?editors=0010โ
Let's recap what happens in this example:
We call ReactDOM.render()
with the <Welcome name="Sara"
/>
element.
React calls the Welcome
component with {name: 'Sara'}
as the props.
Our Welcome
component returns a <h1>Hello,
Sara</h1>
element as the result.
React DOM efficiently updates the DOM
to match <h1>Hello,
Sara</h1>.
Note: Always start component names with a capital letter.React treats components starting with lowercase letters as DOM tags. For example, represents an HTML div tag, but represents a component and requires Welcome to be in scope.To learn more about the reasoning behind this convention, please read JSX In Depth.
Components can refer to other components in their output. This lets us use the same component abstraction for any level of detail. A button, a form, a dialog, a screen: in React apps, all those are commonly expressed as components.
For example, we can create an App
component that renders Welcome
many times:
function Welcome(props) {return <h1>Hello, {props.name}</h1>;}โfunction App() {return (<div> <Welcome name="Sara" /> <Welcome name="Cahal" /> <Welcome name="Edite" /> </div>);}โReactDOM.render(<App />,document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/LYLEWNq?editors=0010โ
Typically, new React apps have a single App
component at the very top. However, if you
integrate React into an existing app, you
might start bottom-up with a small component
like Button
and gradually work your way to the top of
the view hierarchy.
Don't be afraid to split components into smaller components.
For example, consider this Comment
component:
function Comment(props) {return (<div className="Comment"><div className="UserInfo"><img className="Avatar"src={props.author.avatarUrl}alt={props.author.name}/><div className="UserInfo-name">{props.author.name}</div></div><div className="Comment-text">{props.text}</div><div className="Comment-date">{formatDate(props.date)}</div></div>);}
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/PojwpzP?editors=0010โ
It accepts author
(an object), text
(a string), and date
(a date) as props, and describes a comment
on a social media website.
This component can be tricky to change because of all the nesting, and it is also hard to reuse individual parts of it. Let's extract a few components from it.
First, we will extract Avatar:
function Avatar(props) {return (<img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> );}
The Avatar
doesn't need to know that it is being
rendered inside a Comment. This is why we have given its prop a more
generic name: user
rather than author.
We recommend naming props from the component's own point of view rather than the context in which it is being used.
We can now simplify Comment
a tiny bit:
function Comment(props) {return (<div className="Comment"> <div className="UserInfo"> <Avatar user={props.author} /> <div className="UserInfo-name"> {props.author.name}</div> </div> <div className="Comment-text"> {props.text}</div> <div className="Comment-date"> {formatDate(props.date)}</div> </div>);}
Next, we will extract a UserInfo
component that renders an Avatar
next to the user's name:
function UserInfo(props) { return (
<div className="UserInfo">
<Avatar user={props.user} /> <div
className="UserInfo-name">
{props.user.name} </div>
</div> ); }
This lets us simplify Comment
even further:
function Comment(props) {return (<div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text}</div> <div className="Comment-date"> {formatDate(props.date)}</div> </div>);}
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/eYRmvzV?editors=0010โ
Extracting components might seem like grunt
work at first, but having a palette of
reusable components pays off in larger apps.
A good rule of thumb is that if a part of
your UI is used several times (Button, Panel, Avatar), or is complex enough on its own (App, FeedStory, Comment), it is a good candidate to be extracted
to a separate component.
Whether you declare a component
as a function or a class, it must never modify its own props.
Consider this sum
function:
function sum(a, b) {return a + b;}
Such functions are called "pure" because they do not attempt to change their inputs, and always return the same result for the same inputs.
In contrast, this function is impure because it changes its own input:
function withdraw(account, amount) {account.total -= amount;}
React is pretty flexible but it has a single strict rule:
All React components must act like pure functions with respect to their props.
Of course, application UIs are dynamic and change over time. In the next section, we will introduce a new concept of "state". State allows React components to change their output over time in response to user actions, network responses, and anything else, without violating this rule.
Consider the ticking clock example from
one of the previous sections. In
Rendering Elements, we have only learned one way to update
the UI. We call ReactDOM.render()
to change the rendered output:
function tick() {const element = (<div> <h1>Hello, world!</h1> <h2>It is {new Date().toLocaleTimeString()}.</h2> </div>);ReactDOM.render( element, document.getElementById('root') );}โsetInterval(tick, 1000);
โTry it on CodePenโ
In this section, we will learn how to make
the Clock
component truly reusable and encapsulated.
It will set up its own timer and update
itself every second.
We can start by encapsulating how the clock looks:
function Clock(props) {return (<div> <h1>Hello, world!</h1> <h2>It is {props.date.toLocaleTimeString()}.</h2> </div> );}โfunction tick() {ReactDOM.render(<Clock date={new Date()} />, document.getElementById('root'));}โsetInterval(tick, 1000);
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/powvegw?editors=0010โ
However, it misses a crucial requirement:
the fact that the Clock
sets up a timer and updates the UI every
second should be an implementation detail of
the Clock.
Ideally we want to write this once and have
the Clock
update itself:
ReactDOM.render(<Clock />, document.getElementById('root'));
To implement this, we need to add
"state" to the Clock
component.
State is similar to props, but it is private and fully controlled by the component.
You can convert a function component like Clock
to a class in five steps:
Create an
ES6 class, with the same name, that extends React.Component.
Add a single empty method to it
called render().
Move the body of the function into
the render()
method.
Replace props
with this.props
in the render()
body.
Delete the remaining empty function declaration.
class Clock extends React.Component {render() {return (<div><h1>Hello, world!</h1><h2>It is {this.props.date.toLocaleTimeString()}.</h2></div>);}}
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/eYRmvJV?editors=0010โ
Clock
is now defined as a class rather than a
function.
The render
method will be called each time an update
happens, but as long as we render <Clock />
into the same DOM node, only a single
instance of the Clock
class will be used. This lets us use
additional features such as local state and
lifecycle methods.
We will move the date
from props to state in three steps:
Replace this.props.date
with this.state.date
in the render()
method:
class Clock extends React.Component {render() {return (<div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>);}}
Add a
class constructor
that assigns the initial this.state:
class Clock extends React.Component {constructor(props) {super(props);this.state = {date: new Date()}; }โrender() {return (<div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>);}}
Note how we pass props
to the base constructor:
constructor(props) {super(props); this.state = {date: new Date()};}
Class components should always call the
base constructor with props.
Remove the date
prop from the <Clock />
element:
ReactDOM.render(<Clock />, document.getElementById('root'));
We will later add the timer code back to the component itself.
The result looks like this:
class Clock extends React.Component {constructor(props) { super(props); this.state = {date: new Date()}; }render() {return (<div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>);}}โReactDOM.render(<Clock />, document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/oNwgZbV?editors=0010โ
Next, we'll make the Clock
set up its own timer and update itself every
second.
In applications with many components, it's very important to free up resources taken by the components when they are destroyed.
We want to
set up a timer
whenever the Clock
is rendered to the DOM for the first time.
This is called "mounting" in
React.
We also want to
clear that timer
whenever the DOM produced by the Clock
is removed. This is called
"unmounting" in React.
We can declare special methods on the component class to run some code when a component mounts and unmounts:
class Clock extends React.Component {constructor(props) {super(props);this.state = {date: new Date()};}โcomponentDidMount() { } componentWillUnmount() { }render() {return (<div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>);}}
These methods are called "lifecycle methods".
The componentDidMount()
method runs after the component output has
been rendered to the DOM. This is a good
place to set up a timer:
componentDidMount() {this.timerID = setInterval( () => this.tick(), 1000 ); }
Note how we save the timer ID right on this
(this.timerID).
While this.props
is set up by React itself and this.state
has a special meaning, you are free to add
additional fields to the class manually if
you need to store something that
doesn't participate in the data flow
(like a timer ID).
We will tear down the timer in the componentWillUnmount()
lifecycle method:
componentWillUnmount() {clearInterval(this.timerID); }
Finally, we will implement a method called tick()
that the Clock
component will run every second.
It will use this.setState()
to schedule updates to the component local
state:
class Clock extends React.Component {constructor(props) {super(props);this.state = {date: new Date()};}โcomponentDidMount() {this.timerID = setInterval(() => this.tick(),1000);}โcomponentWillUnmount() {clearInterval(this.timerID);}โtick() { this.setState({ date: new Date() }); }render() {return (<div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>);}}โReactDOM.render(<Clock />,document.getElementById('root'));
โTry it on CodePenโ
Now the clock ticks every second.
Let's quickly recap what's going on and the order in which the methods are called:
When <Clock />
is passed to ReactDOM.render(), React calls the constructor of the Clock
component. Since Clock
needs to display the current time, it
initializes this.state
with an object including the current
time. We will later update this
state.
React then calls the Clock
component's render()
method. This is how React learns what
should be displayed on the screen.
React then updates the DOM to match
the Clock's render output.
When the Clock
output is inserted in the DOM, React
calls the componentDidMount()
lifecycle method. Inside it, the Clock
component asks the browser to set up a
timer to call the component's tick()
method once a second.
Every second the browser calls the tick()
method. Inside it, the Clock
component schedules a UI update by
calling setState()
with an object containing the current
time. Thanks to the setState()
call, React knows the state has
changed, and calls the render()
method again to learn what should be
on the screen. This time, this.state.date
in the render()
method will be different, and so the
render output will include the updated
time. React updates the DOM
accordingly.
If the Clock
component is ever removed from the
DOM, React calls the componentWillUnmount()
lifecycle method so the timer is
stopped.
There are three things you should know
about setState().
For example, this will not re-render a component:
// Wrongthis.state.comment = 'Hello';
Instead, use setState():
// Correctthis.setState({comment: 'Hello'});
The only place where you can assign this.state
is the constructor.
React may batch multiple setState()
calls into a single update for
performance.
Because this.props
and this.state
may be updated asynchronously, you should
not rely on their values for calculating the
next state.
For example, this code may fail to update the counter:
// Wrongthis.setState({counter: this.state.counter + this.props.increment,});
To fix it, use a second form of setState()
that accepts a function rather than an
object. That function will receive the
previous state as the first argument, and
the props at the time the update is applied
as the second argument:
// Correctthis.setState((state, props) => ({counter: state.counter + props.increment}));
We used an arrow function above, but it also works with regular functions:
// Correctthis.setState(function(state, props) {return {counter: state.counter + props.increment};});
When you call setState(), React merges the object you provide into
the current state.
For example, your state may contain several independent variables:
constructor(props) {super(props);this.state = {posts: [], comments: [] };}
Then you can update them independently with
separate setState()
calls:
componentDidMount() {fetchPosts().then(response => {this.setState({posts: response.posts });});โfetchComments().then(response => {this.setState({comments: response.comments });});}
The merging is shallow, so this.setState({comments})
leaves this.state.posts
intact, but completely replaces this.state.comments.
Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn't care whether it is defined as a function or a class.
This is why state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it.
A component may choose to pass its state down as props to its child components:
<FormattedDate date={this.state.date} />
The FormattedDate
component would receive the date
in its props and wouldn't know whether
it came from the Clock's state, from the Clock's props, or was typed by hand:
function FormattedDate(props) {return <h2>It is {props.date.toLocaleTimeString()}.</h2>;}
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/GREgWEp?editors=0010โ
This is commonly called a "top-down" or "unidirectional" data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components "below" them in the tree.
If you imagine a component tree as a waterfall of props, each component's state is like an additional water source that joins it at an arbitrary point but also flows down.
To show that all components are truly
isolated, we can create an App
component that renders three <Clock>s:
function App() {return (<div> <Clock /> <Clock /> <Clock /> </div>);}โReactDOM.render(<App />,document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/YzQPZQK?editors=0010โ
Each Clock
sets up its own timer and updates
independently.
In React apps, whether a component is stateful or stateless is considered an implementation detail of the component that may change over time. You can use stateless components inside stateful components, and vice versa.
React events are named using camelCase, rather than lowercase.
With JSX you pass a function as the event handler, rather than a string.
For example, the HTML:
<button onclick="activateLasers()">Activate Lasers</button>
is slightly different in React:
<button onClick={activateLasers}> Activate Lasers</button>
Another difference is that you cannot
return false
to prevent default behavior in React. You
must call preventDefault
explicitly. For example, with plain HTML, to
prevent the default form behavior of
submitting, you can write:
<form onsubmit="console.log('You clicked submit.'); return false"><button type="submit">Submit</button></form>
In React, this could instead be:
function Form() {function handleSubmit(e) {e.preventDefault(); console.log('You clicked submit.');}โreturn (<form onSubmit={handleSubmit}> <button type="submit">Submit</button> </form>);}
Here, e
is a synthetic event. React defines these
synthetic events according to the
W3C spec, so you don't need to worry about
cross-browser compatibility. React events do
not work exactly the same as native events.
See the [SyntheticEvent](<https://reactjs.org/docs/events.html>)
reference guide to learn more.
When using React, you generally don't
need to call addEventListener
to add listeners to a DOM element after it
is created. Instead, just provide a listener
when the element is initially
rendered.
When you define a component using an
ES6 class, a common pattern is for an event handler
to be a method on the class. For example,
this Toggle
component renders a button that lets the
user toggle between "ON" and
"OFF" states:
class Toggle extends React.Component {constructor(props) {super(props);this.state = {isToggleOn: true};โ// This binding is necessary to make `this` work in the callback this.handleClick = this.handleClick.bind(this); }โhandleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); }render() {return (<button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'}</button>);}}โReactDOM.render(<Toggle />,document.getElementById('root'));
โTry it on CodePenโ
You have to be careful about the meaning of this
in JSX callbacks. In JavaScript, class
methods are not
bound
by default. If you forget to bind this.handleClick
and pass it to onClick, this
will be undefined
when the function is actually called.
This is not React-specific behavior; it is
a part of
how functions work in JavaScript. Generally, if you refer to a method
without ()
after it, such as onClick={this.handleClick}, you should bind that method.
If calling bind
annoys you, there are two ways you can get
around this. If you are using the
experimental
public class fields syntax, you can use class fields to correctly
bind callbacks:
class LoggingButton extends React.Component {// This syntax ensures `this` is bound within handleClick. // Warning: this is *experimental* syntax. handleClick = () => { console.log('this is:', this); }render() {return (<button onClick={this.handleClick}> Click me</button>);}}
This syntax is enabled by default in Create React App.
If you aren't using class fields syntax, you can use an arrow function in the callback:
class LoggingButton extends React.Component {handleClick() {console.log('this is:', this);}โrender() {// This syntax ensures `this` is bound within handleClick return ( <button onClick={() => this.handleClick()}> Click me</button>);}}
The problem with this syntax is that a
different callback is created each time the LoggingButton
renders. In most cases, this is fine.
However, if this callback is passed as a
prop to lower components, those components
might do an extra re-rendering. We generally
recommend binding in the constructor or
using the class fields syntax, to avoid this
sort of performance problem.
Inside a loop, it is common to want to pass
an extra parameter to an event handler. For
example, if id
is the row ID, either of the following would
work:
<button onClick={(e) =>
this.deleteRow(id, e)}>Delete
Row</button><button
onClick={this.deleteRow.bind(this,
id)}>Delete Row</button>
The above two lines are equivalent, and use
arrow functions
and [Function.prototype.bind](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind>)
respectively.
In both cases, the e
argument representing the React event will
be passed as a second argument after the ID.
With an arrow function, we have to pass it
explicitly, but with bind
any further arguments are automatically
forwarded.
Conditional rendering in React works the
same way conditions work in JavaScript. Use
JavaScript operators like [if](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else>)
or the
conditional operator
to create elements representing the current
state, and let React update the UI to match
them.
Consider these two components:
function UserGreeting(props) {return <h1>Welcome back!</h1>;}โfunction GuestGreeting(props) {return <h1>Please sign up.</h1>;}
We'll create a Greeting
component that displays either of these
components depending on whether a user is
logged in:
function Greeting(props) {const isLoggedIn = props.isLoggedIn;if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />;}ReactDOM.render(// Try changing to isLoggedIn={true}:<Greeting isLoggedIn={false} />, document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/mdwyWmJ?editors=0011โ
This example renders a different greeting
depending on the value of isLoggedIn
prop.
You can use variables to store elements. This can help you conditionally render a part of the component while the rest of the output doesn't change.
Consider these two new components representing Logout and Login buttons:
function LoginButton(props) {return (<button onClick={props.onClick}>Login</button>);}โfunction LogoutButton(props) {return (<button onClick={props.onClick}>Logout</button>);}
In the example below, we will create a
stateful component
called LoginControl.
It will render either <LoginButton />
or <LogoutButton />
depending on its current state. It will also
render a <Greeting />
from the previous example:
class LoginControl extends React.Component {constructor(props) {super(props);this.handleLoginClick = this.handleLoginClick.bind(this);this.handleLogoutClick = this.handleLogoutClick.bind(this);this.state = {isLoggedIn: false};}โhandleLoginClick() {this.setState({isLoggedIn: true});}โhandleLogoutClick() {this.setState({isLoggedIn: false});}โrender() {const isLoggedIn = this.state.isLoggedIn;let button;if (isLoggedIn) { button = <LogoutButton onClick={this.handleLogoutClick} />; } else { button = <LoginButton onClick={this.handleLoginClick} />; }return (<div> <Greeting isLoggedIn={isLoggedIn} /> {button} </div>);}}โReactDOM.render(<LoginControl />,document.getElementById('root'));
โTry it on CodePenโ
While declaring a variable and using an if
statement is a fine way to conditionally
render a component, sometimes you might want
to use a shorter syntax. There are a few
ways to inline conditions in JSX, explained
below.
You may
embed expressions in JSX
by wrapping them in curly braces. This
includes the JavaScript logical &&
operator. It can be handy for conditionally
including an element:
function Mailbox(props) {const unreadMessages = props.unreadMessages;return (<div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } </div>);}โconst messages = ['React', 'Re: React', 'Re:Re: React'];ReactDOM.render(<Mailbox unreadMessages={messages} />,document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/VwWYppo?editors=0010โ
It works because in JavaScript, true && expression
always evaluates to expression, and false && expression
always evaluates to false.
Therefore, if the condition is true, the element right after &&
will appear in the output. If it is false, React will ignore and skip it.
Note that returning a falsy expression will
still cause the element after &&
to be skipped but will return the falsy
expression. In the example below, <div>0</div>
will be returned by the render method.
render() {const count = 0; return (<div> { count && <h1>Messages: {count}</h1>} </div>);}
Another method for conditionally rendering
elements inline is to use the JavaScript
conditional operator [condition ? true :
false](<https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator>).
In the example below, we use it to conditionally render a small block of text.
render() {const isLoggedIn = this.state.isLoggedIn;return (<div> The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in. </div>);}
It can also be used for larger expressions although it is less obvious what's going on:
render() {const isLoggedIn = this.state.isLoggedIn;return (<div> {isLoggedIn ? <LogoutButton onClick={this.handleLogoutClick} /> : <LoginButton onClick={this.handleLoginClick} /> }</div> );}
Just like in JavaScript, it is up to you to choose an appropriate style based on what you and your team consider more readable. Also remember that whenever conditions become too complex, it might be a good time to extract a component.
In rare cases you might want a component to
hide itself even though it was rendered by
another component. To do this return null
instead of its render output.
In the example below, the <WarningBanner />
is rendered depending on the value of the
prop called warn. If the value of the prop is false, then the component does not render:
function WarningBanner(props) {if (!props.warn) { return null; }return (<div className="warning"> Warning!</div>);}โclass Page extends React.Component {constructor(props) {super(props);this.state = {showWarning: true};this.handleToggleClick = this.handleToggleClick.bind(this);}โhandleToggleClick() {this.setState(state => ({showWarning: !state.showWarning}));}โrender() {return (<div> <WarningBanner warn={this.state.showWarning} /> <button onClick={this.handleToggleClick}> {this.state.showWarning ? 'Hide' : 'Show'}</button> </div>);}}โReactDOM.render(<Page />,document.getElementById('root'));
โTry it on CodePenโ
Returning null
from a component's render
method does not affect the firing of the
component's lifecycle methods. For
instance componentDidUpdate
will still be called.
Given the code below, we use the [map()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map>)
function to take an array of numbers
and double their values. We assign the new
array returned by map()
to the variable doubled
and log it:
const numbers = [1, 2, 3, 4, 5];const doubled = numbers.map((number) => number * 2);console.log(doubled);
This code logs [2, 4, 6, 8, 10]
to the console.
In React, transforming arrays into lists of elements is nearly identical.
You can build collections of elements and
include them in JSX
using curly braces {}.
Below, we loop through the numbers
array using the JavaScript [map()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map>)
function. We return a <li>
element for each item. Finally, we assign
the resulting array of elements to listItems:
const numbers = [1, 2, 3, 4, 5];const listItems = numbers.map((number) => <li>{number}</li>);
We include the entire listItems
array inside a <ul>
element, and
render it to the DOM:
ReactDOM.render(<ul>{listItems}</ul>, document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/eYRmvvr?editors=0011โ
This code displays a bullet list of numbers between 1 and 5.
Usually you would render lists inside a component.
We can refactor the previous example into a
component that accepts an array of numbers
and outputs a list of elements.
function NumberList(props) {const numbers = props.numbers;const listItems = numbers.map((number) => <li>{number}</li> ); return (<ul>{listItems}</ul> );}โconst numbers = [1, 2, 3, 4, 5];ReactDOM.render(<NumberList numbers={numbers} />, document.getElementById('root'));
When you run this code, you'll be given a warning that a key should be provided for list items. A "key" is a special string attribute you need to include when creating lists of elements. We'll discuss why it's important in the next section.
Let's assign a key
to our list items inside numbers.map()
and fix the missing key issue.
function NumberList(props) {const numbers = props.numbers;const listItems = numbers.map((number) =><li key={number.toString()}> {number}</li>);return (<ul>{listItems}</ul>);}โconst numbers = [1, 2, 3, 4, 5];ReactDOM.render(<NumberList numbers={numbers} />,document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/yLXyMMP?editors=0011โ
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
const numbers = [1, 2, 3, 4, 5];const listItems = numbers.map((number) =><li key={number.toString()}> {number}</li>);
The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys:
const todoItems = todos.map((todo) =><li key={todo.id}> {todo.text}</li>);
When you don't have stable IDs for rendered items, you may use the item index as a key as a last resort:
const todoItems = todos.map((todo, index) =>// Only do this if items have no stable IDs <li key={index}> {todo.text}</li>);
We don't recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state. Check out Robin Pokorny's article for an in-depth explanation on the negative impacts of using an index as a key. If you choose not to assign an explicit key to list items then React will default to using indexes as keys.
Here is an in-depth explanation about why keys are necessary if you're interested in learning more.
Keys only make sense in the context of the surrounding array.
For example, if you
extract
a ListItem
component, you should keep the key on the <ListItem />
elements in the array rather than on the <li>
element in the ListItem
itself.
Example: Incorrect Key Usage
function ListItem(props) {const value = props.value;return (// Wrong! There is no need to specify the key here: <li key={value.toString()}> {value}</li>);}โfunction NumberList(props) {const numbers = props.numbers;const listItems = numbers.map((number) =>// Wrong! The key should have been specified here: <ListItem value={number} /> );return (<ul> {listItems}</ul>);}โconst numbers = [1, 2, 3, 4, 5];ReactDOM.render(<NumberList numbers={numbers} />,document.getElementById('root'));
Example: Correct Key Usage
function ListItem(props) {// Correct! There is no need to specify the key here: return <li>{props.value}</li>;}โfunction NumberList(props) {const numbers = props.numbers;const listItems = numbers.map((number) =>// Correct! Key should be specified inside the array. <ListItem key={number.toString()} value={number} /> );return (<ul> {listItems}</ul>);}โconst numbers = [1, 2, 3, 4, 5];ReactDOM.render(<NumberList numbers={numbers} />,document.getElementById('root'));
โTry it on CodePenโ
A good rule of thumb is that elements
inside the map()
call need keys.
Keys used within arrays should be unique among their siblings. However, they don't need to be globally unique. We can use the same keys when we produce two different arrays:
function Blog(props) {const sidebar = ( <ul> {props.posts.map((post) =><li key={post.id}> {post.title}</li>)}</ul>);const content = props.posts.map((post) => <div key={post.id}> <h3>{post.title}</h3> <p>{post.content}</p> </div>);return (<div> {sidebar} <hr /> {content} </div>);}โconst posts = [{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},{id: 2, title: 'Installation', content: 'You can install React from npm.'}];ReactDOM.render(<Blog posts={posts} />,document.getElementById('root'));
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/mdwyWWy?editors=0010โ
Keys serve as a hint to React but they don't get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:
const content = posts.map((post) =><Post key={post.id} id={post.id} title={post.title} />);
With the example above, the Post
component can read props.id, but not props.key.
In the examples above we declared a
separate listItems
variable and included it in JSX:
function NumberList(props) {const numbers = props.numbers;const listItems = numbers.map((number) => <ListItem key={number.toString()} value={number} /> ); return (<ul> {listItems}</ul>);}
JSX allows
embedding any expression
in curly braces so we could inline the map()
result:
function NumberList(props) {const numbers = props.numbers;return (<ul> {numbers.map((number) => <ListItem key={number.toString()} value={number} /> )} </ul>);}
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/JjJoWEw?editors=0010โ
Sometimes this results in clearer code, but
this style can also be abused. Like in
JavaScript, it is up to you to decide
whether it is worth extracting a variable
for readability. Keep in mind that if the map()
body is too nested, it might be a good time
to
extract a component.
<form><label>Name:<input type="text" name="name" /></label><input type="submit" value="Submit" /></form>
This form has the default HTML form behavior of browsing to a new page when the user submits the form. If you want this behavior in React, it just works. But in most cases, it's convenient to have a JavaScript function that handles the submission of the form and has access to the data that the user entered into the form. The standard way to achieve this is with a technique called "controlled components".
In HTML, form elements such as <input>, <textarea>, and <select>
typically maintain their own state and
update it based on user input. In React,
mutable state is typically kept in the state
property of components, and only updated
with [setState()](<https://reactjs.org/docs/react-component.html#setstate>).
We can combine the two by making the React state be the "single source of truth". Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a "controlled component".
For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component:
class NameForm extends React.Component {constructor(props) {super(props);this.state = {value: ''};this.handleChange = this.handleChange.bind(this);this.handleSubmit = this.handleSubmit.bind(this);}โhandleChange(event) { this.setState({value: event.target.value}); }handleSubmit(event) {alert('A name was submitted: ' + this.state.value);event.preventDefault();}โrender() {return (<form onSubmit={this.handleSubmit}> <label> Name:<input type="text" value={this.state.value} onChange={this.handleChange} /> </label> <input type="submit" value="Submit" /> </form>);}}
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/rNwayjv?editors=0010โ
Since the value
attribute is set on our form element, the
displayed value will always be this.state.value, making the React state the source of
truth. Since handleChange
runs on every keystroke to update the React
state, the displayed value will update as
the user types.
With a controlled component, the input's value is always driven by the React state. While this means you have to type a bit more code, you can now pass the value to other UI elements too, or reset it from other event handlers.
In HTML, a <textarea>
element defines its text by its
children:
<textarea>Hello there, this is some text in a text area</textarea>
In React, a <textarea>
uses a value
attribute instead. This way, a form using a <textarea>
can be written very similarly to a form that
uses a single-line input:
class EssayForm extends React.Component {constructor(props) {super(props);this.state = { value: 'Please write an essay about your favorite DOM element.' };this.handleChange = this.handleChange.bind(this);this.handleSubmit = this.handleSubmit.bind(this);}โhandleChange(event) { this.setState({value: event.target.value}); }handleSubmit(event) {alert('An essay was submitted: ' + this.state.value);event.preventDefault();}โrender() {return (<form onSubmit={this.handleSubmit}> <label> Essay:<textarea value={this.state.value} onChange={this.handleChange} /> </label> <input type="submit" value="Submit" /> </form>);}}
Notice that this.state.value
is initialized in the constructor, so that
the text area starts off with some text in
it.
In HTML, <select>
creates a drop-down list. For example, this
HTML creates a drop-down list of
flavors:
<select><option
value="grapefruit">Grapefruit</option><option
value="lime">Lime</option><option
selected
value="coconut">Coconut</option><option
value="mango">Mango</option></select>
Note that the Coconut option is initially
selected, because of the selected
attribute. React, instead of using this selected
attribute, uses a value
attribute on the root select
tag. This is more convenient in a controlled
component because you only need to update it
in one place. For example:
class FlavorForm extends React.Component {constructor(props) {super(props);this.state = {value: 'coconut'};this.handleChange = this.handleChange.bind(this);this.handleSubmit = this.handleSubmit.bind(this);}โhandleChange(event) { this.setState({value: event.target.value}); }handleSubmit(event) {alert('Your favorite flavor is: ' + this.state.value);event.preventDefault();}โrender() {return (<form onSubmit={this.handleSubmit}> <label> Pick your favorite flavor:<select value={this.state.value} onChange={this.handleChange}> <option value="grapefruit">Grapefruit</option> <option value="lime">Lime</option> <option value="coconut">Coconut</option> <option value="mango">Mango</option> </select> </label> <input type="submit" value="Submit" /> </form>);}}
โTry it on CodePenโ
Overall, this makes it so that <input type="text">, <textarea>, and <select>
all work very similarly - they all accept a value
attribute that you can use to implement a
controlled component.
NoteYou can pass an array into the value attribute, allowing you to select multiple options in a select tag:
In HTML, an <input type="file">
lets the user choose one or more files from
their device storage to be uploaded to a
server or manipulated by JavaScript via the
File API.
<input type="file"
/>
Because its value is read-only, it is an uncontrolled component in React. It is discussed together with other uncontrolled components later in the documentation.
When you need to handle multiple controlled input
elements, you can add a name
attribute to each element and let the
handler function choose what to do based on
the value of event.target.name.
For example:
class Reservation extends React.Component {constructor(props) {super(props);this.state = {isGoing: true,numberOfGuests: 2};โthis.handleInputChange = this.handleInputChange.bind(this);}โhandleInputChange(event) {const target = event.target;const value = target.type === 'checkbox' ? target.checked : target.value;const name = target.name;this.setState({[name]: value });}โrender() {return (<form> <label> Is going:<inputname="isGoing" type="checkbox"checked={this.state.isGoing}onChange={this.handleInputChange} /> </label> <br /> <label> Number of guests:<inputname="numberOfGuests" type="number"value={this.state.numberOfGuests}onChange={this.handleInputChange} /> </label> </form>);}}
โTry it on CodePenโ
Note how we used the ES6 computed property name syntax to update the state key corresponding to the given input name:
this.setState({
It is equivalent to this ES5 code:
var partialState = {};partialState[name] = value;this.setState(partialState);
Also, since setState()
automatically
merges a partial state into the current
state, we only needed to call it with the
changed parts.
Specifying the value prop on a
controlled component
prevents the user from changing the input
unless you desire so. If you've
specified a value
but the input is still editable, you may
have accidentally set value
to undefined
or null.
The following code demonstrates this. (The input is locked at first but becomes editable after a short delay.)
ReactDOM.render(<input value="hi" />, mountNode);โsetTimeout(function() {ReactDOM.render(<input value={null} />, mountNode);}, 1000);
It can sometimes be tedious to use controlled components, because you need to write an event handler for every way your data can change and pipe all of the input state through a React component. This can become particularly annoying when you are converting a preexisting codebase to React, or integrating a React application with a non-React library. In these situations, you might want to check out uncontrolled components, an alternative technique for implementing input forms.
If you're looking for a complete solution including validation, keeping track of the visited fields, and handling form submission, Formik is one of the popular choices. However, it is built on the same principles of controlled components and managing state --- so don't neglect to learn them.
In this section, we will create a temperature calculator that calculates whether the water would boil at a given temperature.
We will start with a component called BoilingVerdict. It accepts the celsius
temperature as a prop, and prints whether it
is enough to boil the water:
function BoilingVerdict(props) {if (props.celsius >= 100) {return <p>The water would boil.</p>; }return <p>The water would not boil.</p>;}
Next, we will create a component called Calculator. It renders an <input>
that lets you enter the temperature, and
keeps its value in this.state.temperature.
Additionally, it renders the BoilingVerdict
for the current input value.
class Calculator extends React.Component {constructor(props) {super(props);this.handleChange = this.handleChange.bind(this);this.state = {temperature: ''}; }โhandleChange(e) {this.setState({temperature: e.target.value}); }โrender() {const temperature = this.state.temperature; return (<fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> <BoilingVerdict celsius={parseFloat(temperature)} /> </fieldset>);}}
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/zYzxZoL?editors=0010โ
Our new requirement is that, in addition to a Celsius input, we provide a Fahrenheit input, and they are kept in sync.
We can start by extracting a TemperatureInput
component from Calculator. We will add a new scale
prop to it that can either be "c"
or "f":
const scaleNames = { c: 'Celsius', f: 'Fahrenheit'};class TemperatureInput extends React.Component {constructor(props) {super(props);this.handleChange = this.handleChange.bind(this);this.state = {temperature: ''};}โhandleChange(e) {this.setState({temperature: e.target.value});}โrender() {const temperature = this.state.temperature;const scale = this.props.scale; return (<fieldset> <legend>Enter temperature in {scaleNames[scale]}:</legend> <input value={temperature}onChange={this.handleChange} /> </fieldset>);}}
We can now change the Calculator
to render two separate temperature
inputs:
class Calculator extends React.Component {render() {return (<div> <TemperatureInput scale="c" /> <TemperatureInput scale="f" /> </div>);}}
โTry it on CodePenโ
โhttps://codepen.io/bgoonz/pen/QWgwpGv?editors=0010โ
We have two inputs now, but when you enter the temperature in one of them, the other doesn't update. This contradicts our requirement: we want to keep them in sync.
We also can't display the BoilingVerdict
from Calculator. The Calculator
doesn't know the current temperature
because it is hidden inside the TemperatureInput.
First, we will write two functions to convert from Celsius to Fahrenheit and back:
function toCelsius(fahrenheit) {return (fahrenheit - 32) * 5 / 9;}โfunction toFahrenheit(celsius) {return (celsius * 9 / 5) + 32;}
These two functions convert numbers. We
will write another function that takes a
string temperature
and a converter function as arguments and
returns a string. We will use it to
calculate the value of one input based on
the other input.
It returns an empty string on an invalid temperature, and it keeps the output rounded to the
third decimal place:
function tryConvert(temperature, convert) {const input = parseFloat(temperature);if (Number.isNaN(input)) {return '';}const output = convert(input);const rounded = Math.round(output * 1000) / 1000;return rounded.toString();}
For example, tryConvert('abc',
toCelsius)
returns an empty string, and tryConvert('10.22',
toFahrenheit)
returns '50.396'.
Currently, both TemperatureInput
components independently keep their values
in the local state:
class TemperatureInput extends React.Component {constructor(props) {super(props);this.handleChange = this.handleChange.bind(this);this.state = {temperature: ''}; }โhandleChange(e) {this.setState({temperature: e.target.value}); }โrender() {const temperature = this.state.temperature; // ...
However, we want these two inputs to be in sync with each other. When we update the Celsius input, the Fahrenheit input should reflect the converted temperature, and vice versa.
In React, sharing state is accomplished by
moving it up to the closest common ancestor
of the components that need it. This is
called "lifting state up". We will
remove the local state from the TemperatureInput
and move it into the Calculator
instead.
If the Calculator
owns the shared state, it becomes the
"source of truth" for the current
temperature in both inputs. It can instruct
them both to have values that are consistent
with each other. Since the props of both TemperatureInput
components are coming from the same parent Calculator
component, the two inputs will always be in
sync.
Let's see how this works step by step.
First, we will replace this.state.temperature
with this.props.temperature
in the TemperatureInput
component. For now, let's pretend this.props.temperature
already exists, although we will need to
pass it from the Calculator
in the future:
render() {// Before: const temperature = this.state.temperature;const temperature = this.props.temperature; // ...
We know that
props are read-only. When the temperature
was in the local state, the TemperatureInput
could just call this.setState()
to change it. However, now that the temperature
is coming from the parent as a prop, the TemperatureInput
has no control over it.
In React, this is usually solved by making
a component "controlled". Just
like the DOM <input>
accepts both a value
and an onChange
prop, so can the custom TemperatureInput
accept both temperature
and onTemperatureChange
props from its parent Calculator.
Now, when the TemperatureInput
wants to update its temperature, it calls this.props.onTemperatureChange:
handleChange(e) {// Before: this.setState({temperature: e.target.value});this.props.onTemperatureChange(e.target.value); // ...
Note:There is no special meaning to either temperature or onTemperatureChange prop names in custom components. We could have called them anything else, like name them value and onChange which is a common convention.
The onTemperatureChange
prop will be provided together with the temperature
prop by the parent Calculator
component. It will handle the change by
modifying its own local state, thus
re-rendering both inputs with the new
values. We will look at the new Calculator
implementation very soon.
Before diving into the changes in the Calculator, let's recap our changes to the TemperatureInput
component. We have removed the local state
from it, and instead of reading this.state.temperature, we now read this.props.temperature. Instead of calling this.setState()
when we want to make a change, we now call this.props.onTemperatureChange(), which will be provided by the Calculator:
class TemperatureInput extends React.Component {constructor(props) {super(props);this.handleChange = this.handleChange.bind(this);}โhandleChange(e) {this.props.onTemperatureChange(e.target.value); }โrender() {const temperature = this.props.temperature; const scale = this.props.scale;return (<fieldset> <legend>Enter temperature in {scaleNames[scale]}:</legend> <input value={temperature}onChange={this.handleChange} /> </fieldset>);}}
Now let's turn to the Calculator
component.
We will store the current input's temperature
and scale
in its local state. This is the state we
"lifted up" from the inputs, and
it will serve as the "source of
truth" for both of them. It is the
minimal representation of all the data we
need to know in order to render both
inputs.
For example, if we enter 37 into the
Celsius input, the state of the Calculator
component will be:
{temperature: '37',scale: 'c'}
If we later edit the Fahrenheit field to be
212, the state of the Calculator
will be:
{temperature: '212',scale: 'f'}
We could have stored the value of both
inputs but it turns out to be unnecessary.
It is enough to store the value of the most
recently changed input, and the scale that
it represents. We can then infer the value
of the other input based on the current temperature
and scale
alone.
The inputs stay in sync because their values are computed from the same state:
class Calculator extends React.Component {constructor(props) {super(props);this.handleCelsiusChange = this.handleCelsiusChange.bind(this);this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);this.state = {temperature: '', scale: 'c'}; }โhandleCelsiusChange(temperature) {this.setState({scale: 'c', temperature}); }โhandleFahrenheitChange(temperature) {this.setState({scale: 'f', temperature}); }โrender() {const scale = this.state.scale; const temperature = this.state.temperature; const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature; const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;return (<div> <TemperatureInputscale="c" temperature={celsius} onTemperatureChange={this.handleCelsiusChange} /> <TemperatureInputscale="f" temperature={fahrenheit} onTemperatureChange={this.handleFahrenheitChange} /> <BoilingVerdict celsius={parseFloat(celsius)} /> </div>);}}
โTry it on CodePenโ
Now, no matter which input you edit, this.state.temperature
and this.state.scale
in the Calculator
get updated. One of the inputs gets the
value as is, so any user input is preserved,
and the other input value is always
recalculated based on it.
Let's recap what happens when you edit an input:
React calls the function specified as onChange
on the DOM <input>. In our case, this is the handleChange
method in the TemperatureInput
component.
The handleChange
method in the TemperatureInput
component calls this.props.onTemperatureChange()
with the new desired value. Its props,
including onTemperatureChange, were provided by its parent
component, the Calculator.
When it previously rendered, the Calculator
had specified that onTemperatureChange
of the Celsius TemperatureInput
is the Calculator's handleCelsiusChange
method, and onTemperatureChange
of the Fahrenheit TemperatureInput
is the Calculator's handleFahrenheitChange
method. So either of these two Calculator
methods gets called depending on which
input we edited.
Inside these methods, the Calculator
component asks React to re-render
itself by calling this.setState()
with the new input value and the
current scale of the input we just
edited.
React calls the Calculator
component's render
method to learn what the UI should
look like. The values of both inputs
are recomputed based on the current
temperature and the active scale. The
temperature conversion is performed
here.
React calls the render
methods of the individual TemperatureInput
components with their new props
specified by the Calculator. It learns what their UI should look
like.
React calls the render
method of the BoilingVerdict
component, passing the temperature in
Celsius as its props.
React DOM updates the DOM with the boiling verdict and to match the desired input values. The input we just edited receives its current value, and the other input is updated to the temperature after conversion.
Every update goes through the same steps so the inputs stay in sync.
There should be a single "source of truth" for any data that changes in a React application. Usually, the state is first added to the component that needs it for rendering. Then, if other components also need it, you can lift it up to their closest common ancestor. Instead of trying to sync the state between different components, you should rely on the top-down data flow.
Lifting state involves writing more "boilerplate" code than two-way binding approaches, but as a benefit, it takes less work to find and isolate bugs. Since any state "lives" in some component and that component alone can change it, the surface area for bugs is greatly reduced. Additionally, you can implement any custom logic to reject or transform user input.
If something can be derived from either
props or state, it probably shouldn't
be in the state. For example, instead of
storing both celsiusValue
and fahrenheitValue, we store just the last edited temperature
and its scale. The value of the other input can always
be calculated from them in the render()
method. This lets us clear or apply rounding
to the other field without losing any
precision in the user input.
When you see something wrong in the UI, you can use React Developer Tools to inspect the props and move up the tree until you find the component responsible for updating the state. This lets you trace the bugs to their source:
In this section, we will consider a few problems where developers new to React often reach for inheritance, and show how we can solve them with composition.
Some components don't know their
children ahead of time. This is especially
common for components like Sidebar
or Dialog
that represent generic
"boxes".
We recommend that such components use the
special children
prop to pass children elements directly into
their output:
function FancyBorder(props) {return (<div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div>);}
This lets other components pass arbitrary children to them by nesting the JSX:
function WelcomeDialog() {return (<FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder>);}
โTry it on CodePenโ
Anything inside the <FancyBorder>
JSX tag gets passed into the FancyBorder
component as a children
prop. Since FancyBorder
renders {props.children}
inside a <div>, the passed elements appear in the final
output.
While this is less common, sometimes you
might need multiple "holes" in a
component. In such cases you may come up
with your own convention instead of using children:
function SplitPane(props) {return (<div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div>);}โfunction App() {return (<SplitPaneleft={<Contacts /> }right={<Chat /> } />);}
โTry it on CodePenโ
React elements like <Contacts />
and <Chat />
are just objects, so you can pass them as
props like any other data. This approach may
remind you of "slots" in other
libraries but there are no limitations on
what you can pass as props in React.
Sometimes we think about components as
being "special cases" of other
components. For example, we might say that a WelcomeDialog
is a special case of Dialog.
In React, this is also achieved by composition, where a more "specific" component renders a more "generic" one and configures it with props:
function Dialog(props) {return (<FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> </FancyBorder>);}โfunction WelcomeDialog() {return (<Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> );}
โTry it on CodePenโ
Composition works equally well for components defined as classes:
function Dialog(props) {return (<FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title}</h1> <p className="Dialog-message"> {props.message}</p> {props.children} </FancyBorder>);}โclass SignUpDialog extends React.Component {constructor(props) {super(props);this.handleChange = this.handleChange.bind(this);this.handleSignUp = this.handleSignUp.bind(this);this.state = {login: ''};}โrender() {return (<Dialog title="Mars Exploration Program"message="How should we refer to you?"> <input value={this.state.login} onChange={this.handleChange} /> <button onClick={this.handleSignUp}> Sign Me Up! </button> </Dialog>);}โhandleChange(e) {this.setState({login: e.target.value});}โhandleSignUp() {alert(`Welcome aboard, ${this.state.login}!`);}}
โTry it on CodePenโ
At Facebook, we use React in thousands of components, and we haven't found any use cases where we would recommend creating component inheritance hierarchies.
Props and composition give you all the flexibility you need to customize a component's look and behavior in an explicit and safe way. Remember that components may accept arbitrary props, including primitive values, React elements, or functions.
If you want to reuse non-UI functionality between components, we suggest extracting it into a separate JavaScript module. The components may import it and use that function, object, or a class, without extending it.
One of the many great parts of React is how it makes you think about apps as you build them. In this document, we'll walk you through the thought process of building a searchable product data table using React.
Imagine that we already have a JSON API and a mock from our designer. The mock looks like this:
Our JSON API returns some data that looks like this:
[{category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},{category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},{category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},{category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},{category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},{category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}];
The first thing you'll want to do is to draw boxes around every component (and subcomponent) in the mock and give them all names. If you're working with a designer, they may have already done this, so go talk to them! Their Photoshop layer names may end up being the names of your React components!
But how do you know what should be its own component? Use the same techniques for deciding if you should create a new function or object. One such technique is the single responsibility principle, that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents.
Since you're often displaying a JSON data model to a user, you'll find that if your model was built correctly, your UI (and therefore your component structure) will map nicely. That's because UI and data models tend to adhere to the same information architecture. Separate your UI into components, where each component matches one piece of your data model.
You'll see here that we have five components in our app. We've italicized the data each component represents.
FilterableProductTable
(orange):
contains the entirety of the
example
SearchBar
(blue):
receives all user input
ProductTable
(green):
displays and filters the data collection
based on user input
ProductCategoryRow
(turquoise):
displays a heading for each category
ProductRow
(red):
displays a row for each product
If you look at ProductTable, you'll see that the table header
(containing the "Name" and
"Price" labels) isn't its own
component. This is a matter of preference,
and there's an argument to be made
either way. For this example, we left it as
part of ProductTable
because it is part of rendering the data collection
which is ProductTable's responsibility. However, if this
header grows to be complex (e.g., if we were
to add affordances for sorting), it would
certainly make sense to make this its own ProductTableHeader
component.
Now that we've identified the components in our mock, let's arrange them into a hierarchy. Components that appear within another component in the mock should appear as a child in the hierarchy:
FilterableProductTable
SearchBar
ProductTable
ProductCategoryRow
ProductRow
See the Pen Thinking In React: Step 2 on CodePen.
Now that you have your component hierarchy, it's time to implement your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why.
To build a static version of your app that renders your data model, you'll want to build components that reuse other components and pass data using props. props are a way of passing data from parent to child. If you're familiar with the concept of state, don't use state at all to build this static version. State is reserved only for interactivity, that is, data that changes over time. Since this is a static version of the app, you don't need it.
You can build top-down or bottom-up. That
is, you can either start with building the
components higher up in the hierarchy (i.e.
starting with FilterableProductTable) or with the ones lower in it (ProductRow). In simpler examples, it's usually
easier to go top-down, and on larger
projects, it's easier to go bottom-up
and write tests as you build.
At the end of this step, you'll have a
library of reusable components that render
your data model. The components will only
have render()
methods since this is a static version of
your app. The component at the top of the
hierarchy (FilterableProductTable) will take your data model as a prop. If
you make a change to your underlying data
model and call ReactDOM.render()
again, the UI will be updated. You can see
how your UI is updated and where to make
changes. React's one-way data flow
(also called one-way binding) keeps everything modular and fast.
Refer to the React docs if you need help executing this step.
There are two types of "model" data in React: props and state. It's important to understand the distinction between the two; skim the official React docs if you aren't sure what the difference is. See also FAQ: What is the difference between state and props?โ
To make your UI interactive, you need to be able to trigger changes to your underlying data model. React achieves this with state.
To build your app correctly, you first need to think of the minimal set of mutable state that your app needs. The key here is DRY: Don't Repeat Yourself. Figure out the absolute minimal representation of the state your application needs and compute everything else you need on-demand. For example, if you're building a TODO list, keep an array of the TODO items around; don't keep a separate state variable for the count. Instead, when you want to render the TODO count, take the length of the TODO items array.
Think of all the pieces of data in our example application. We have:
The original list of products
The search text the user has entered
The value of the checkbox
The filtered list of products
Let's go through each one and figure out which one is state. Ask three questions about each piece of data:
Is it passed in from a parent via props? If so, it probably isn't state.
Does it remain unchanged over time? If so, it probably isn't state.
Can you compute it based on any other state or props in your component? If so, it isn't state.
The original list of products is passed in as props, so that's not state. The search text and the checkbox seem to be state since they change over time and can't be computed from anything. And finally, the filtered list of products isn't state because it can be computed by combining the original list of products with the search text and value of the checkbox.
So finally, our state is:
The search text the user has entered
The value of the checkbox
See the Pen Thinking In React: Step 4 on CodePen.
OK, so we've identified what the minimal set of app state is. Next, we need to identify which component mutates, or owns, this state.
Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. This is often the most challenging part for newcomers to understand, so follow these steps to figure it out:
For each piece of state in your application:
Identify every component that renders something based on that state.
Find a common owner component (a single component above all the components that need the state in the hierarchy).
Either the common owner or another component higher up in the hierarchy should own the state.
If you can't find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common owner component.
Let's run through this strategy for our application:
ProductTable
needs to filter the product list based
on state and SearchBar
needs to display the search text and
checked state.
The common owner component is FilterableProductTable.
It conceptually makes sense for the
filter text and checked value to live
in FilterableProductTable
Cool, so we've decided that our state
lives in FilterableProductTable. First, add an instance property this.state = {filterText: '',
inStockOnly: false}
to FilterableProductTable's constructor
to reflect the initial state of your
application. Then, pass filterText
and inStockOnly
to ProductTable
and SearchBar
as a prop. Finally, use these props to
filter the rows in ProductTable
and set the values of the form fields in SearchBar.
You can start seeing how your application
will behave: set filterText
to "ball"
and refresh your app. You'll see that
the data table is updated correctly.
See the Pen Thinking In React: Step 5 on CodePen.
So far, we've built an app that
renders correctly as a function of props and
state flowing down the hierarchy. Now
it's time to support data flowing the
other way: the form components deep in the
hierarchy need to update the state in FilterableProductTable.
React makes this data flow explicit to help you understand how your program works, but it does require a little more typing than traditional two-way data binding.
If you try to type or check the box in the
current version of the example, you'll
see that React ignores your input. This is
intentional, as we've set the value
prop of the input
to always be equal to the state
passed in from FilterableProductTable.
Let's think about what we want to
happen. We want to make sure that whenever
the user changes the form, we update the
state to reflect the user input. Since
components should only update their own
state, FilterableProductTable
will pass callbacks to SearchBar
that will fire whenever the state should be
updated. We can use the onChange
event on the inputs to be notified of it.
The callbacks passed by FilterableProductTable
will call setState(), and the app will be updated.
Hopefully, this gives you an idea of how to think about building components and applications with React. While it may be a little more typing than you're used to, remember that code is read far more than it's written, and it's less difficult to read this modular, explicit code. As you start to build large libraries of components, you'll appreciate this explicitness and modularity, and with code reuse, your lines of code will start to shrink. :)
โAdvanced Contentโ
โReact Componentโ
โ
This appendix is a non-exhaustive list of new syntactic features and methods that were added to JavaScript in ES6. These features are the most commonly used and most helpful.
While this appendix doesn't cover ES6 classes, we go over the basics while learning about components in the book. In addition, this appendix doesn't include descriptions of some larger new features like promises and generators. If you'd like more info on those or on any topic below, we encourage you to reference the Mozilla Developer Network's website (MDN).
If you've worked with ES5 JavaScript
before, you're likely used to seeing
variables declared with var:
var myVariable = 5;
Both the const
and let
statements also declare variables. They were
introduced in ES6.
Use const
in cases where a variable is never
re-assigned. Using const
makes this clear to whoever is reading your
code. It refers to the "constant"
state of the variable in the context it is
defined within.
If the variable will be re-assigned, use let.
We encourage the use of const
and let
instead of var. In addition to the restriction introduced
by const, both const
and let
are block scoped
as opposed to function scoped. This scoping can help avoid unexpected
bugs.
There are three ways to write arrow function bodies. For the examples below, let's say we have an array of city objects:
onst cities = [{ name: 'Cairo', pop: 7764700 },{ name: 'Lagos', pop: 8029200 },];
If we write an arrow function that spans multiple lines, we must use braces to delimit the function body like this:
const formattedPopulations = cities.map((city) => {const popMM = (city.pop / 1000000).toFixed(2);return popMM + ' million';});console.log(formattedPopulations);
Note that we must also explicitly specify a return
for the function.
However, if we write a function body that is only a single line (or single expression) we can use parentheses to delimit it:
const formattedPopulations2 = cities.map((city) => ((city.pop / 1000000).toFixed(2) + ' million'));
Notably, we don't use return
as it's implied.
Furthermore, if your function body is terse you can write it like so:
const pops = cities.map(city => city.pop);console.log(pops);
The terseness of arrow functions is one of two reasons that we use them. Compare the one-liner above to this:
const popsNoArrow = cities.map(function(city) { return city.pop });
Of greater benefit, though, is how arrow
functions bind the this
object.
The traditional JavaScript function
declaration syntax (function () {}) will bind this
in anonymous functions to the global object.
To illustrate the confusion this causes,
consider the following example:
unction printSong() {console.log("Oops - The Global Object");}โconst jukebox = {songs: [{title: "Wanna Be Startin' Somethin'",artist: "Michael Jackson",},{title: "Superstar",artist: "Madonna",},],printSong: function (song) {console.log(song.title + " - " + song.artist);},printSongs: function () {โthis.songs.forEach(function(song) {โthis.printSong(song);});},}โjukebox.printSongs();
The method printSongs()
iterates over this.songs
with forEach(). In this context, this
is bound to the object (jukebox) as expected. However, the anonymous
function passed to forEach()
binds its internal this
to the global object. As such, this.printSong(song)
calls the function declared at the top of
the example, not
the method on jukebox.
JavaScript developers have traditionally
used workarounds for this behavior, but
arrow functions solve the problem by capturing the
this
value of the enclosing context. Using an arrow function for printSongs()
has the expected result:
printSongs: function () {this.songs.forEach((song) => {โthis.printSong(song);});},}โjukebox.printSongs();
For this reason, throughout the book we use arrow functions for all anonymous functions.
ES6 formally supports modules using the import/export
syntax.
Named exports
Inside any file, you can use export
to specify a variable the module should
expose. Here's an example of a file
that exports two functions:
export const sayHi = () => (console.log('Hi!'));export const sayBye = () => (console.log('Bye!'));โconst saySomething = () => (console.log('Something!'));
Now, anywhere we wanted to use these
functions we could use import. We need to specify which functions we
want to import. A common way of doing this
is using ES6's destructuring assignment
syntax to list them out like this:
import { sayHi, sayBye } from './greetings';โsayHi();sayBye();
Importantly, the function that was not
exported (saySomething) is unavailable outside of the
module.
Also note that we supply a relative path
to from, indicating that the ES6 module is a local
file as opposed to an npm package.
Instead of inserting an export
before each variable you'd like to
export, you can use this syntax to list off
all the exposed variables in one area:
const sayHi = () => (console.log('Hi!'));const sayBye = () => (console.log('Bye!'));โconst saySomething = () => (console.log('Something!'));โexport { sayHi, sayBye };
We can also specify that we'd like to
import all of a module's functionality
underneath a given namespace with the import * as <Namespace>
syntax:
import * as Greetings from './greetings';โGreetings.sayHi();โGreetings.sayBye();โGreetings.saySomething();
Default export
The other type of export is a default export. A module can only contain one default export:
const sayHi = () => (console.log('Hi!'));const sayBye = () => (console.log('Bye!'));โconst saySomething = () => (console.log('Something!'));โconst Greetings = { sayHi, sayBye };โexport default Greetings;
This is a common pattern for libraries. It means you can easily import the library wholesale without specifying what individual functions you want:
import Greetings from './greetings';โGreetings.sayHi();Greetings.sayBye();
It's not uncommon for a module to use
a mix of both named exports and default
exports. For instance, with react-dom, you can import ReactDOM
(a default export) like this:
import ReactDOM from 'react-dom';โReactDOM.render(โ);
Or, if you're only going to use the render()
function, you can import the named render()
function like this:
import { render } from 'react-dom';โrender(โ);
To achieve this flexibility, the export
implementation for react-dom
looks something like this:
export const render = (component, target) => {โ};โconst ReactDOM = {render,โ};โexport default ReactDOM;
If you want to play around with the module
syntax, check out the folder code/webpack/es6-modules.
For more reading on ES6 modules, see this article from Mozilla: "ES6 in Depth: Modules".
We use Object.assign()
often throughout the book. We use it in
areas where we want to create a modified
version of an existing object.
Object.assign()
accepts any number of objects as arguments.
When the function receives two arguments, it copies
the properties of the second object onto the
first, like so:
onst coffee = { };const noCream = { cream: false };const noMilk = { milk: false };Object.assign(coffee, noCream);
It is idiomatic to pass in three arguments
to Object.assign(). The first argument is a new JavaScript
object, the one that Object.assign()
will ultimately return. The second is the
object whose properties we'd like to
build off of. The last is the changes
we'd like to apply:
const coffeeWithMilk = Object.assign({}, coffee, { milk: true });
Object.assign()
is a handy method for working with
"immutable" JavaScript
objects.
In ES5 JavaScript, you'd interpolate variables into strings like this:
var greeting = 'Hello, ' + user + '! It is ' + degF + ' degrees outside.';
With ES6 template literals, we can create the same string like this:
const greeting = `Hello, ${user}! It is ${degF} degrees outside.`;
In arrays, the ellipsis ...
operator will expand
the array that follows into the parent
array. The spread operator enables us to
succinctly construct new arrays as a
composite of existing arrays.
Here is an example:
const a = [ 1, 2, 3 ];const b = [ 4, 5, 6 ];const c = [ ...a, ...b, 7, 8, 9 ];โconsole.log(c);
Notice how this is different than if we wrote:
const d = [ a, b, 7, 8, 9 ];console.log(d);
In ES5, all objects were required to have explicit key and value declarations:
const explicit = {getState: getState,dispatch: dispatch,};
In ES6, you can use this terser syntax whenever the property name and variable name are the same:
const implicit = {getState,dispatch,};
Lots of open source libraries use this syntax, so it's good to be familiar with it. But whether you use it in your own code is a matter of stylistic preference.
With ES6, you can specify a default value
for an argument in the case that it is undefined
when the function is called.
This:
unction divide(a, b) {โconst divisor = typeof b === 'undefined' ? 1 : b;โreturn a / divisor;}
Can be written as this:
function divide(a, b = 1) {return a / b;}
In both cases, using the function looks like this:
divide(14, 2);โdivide(14, undefined);โdivide(14);
Whenever the argument b
in the example above is undefined, the default argument is used. Note that null
will not use the default argument:
divide(14, null);
For arrays
In ES5, extracting and assigning multiple elements from an array looked like this:
ar fruits = [ 'apples', 'bananas', 'oranges' ];var fruit1 = fruits[0];var fruit2 = fruits[1];
In ES6, we can use the destructuring syntax to accomplish the same task like this:
const [ veg1, veg2 ] = [ 'asparagus', 'broccoli', 'onion' ];console.log(veg1);console.log(veg2);
The variables in the array on the left are
"matched" and assigned to the
corresponding elements in the array on the
right. Note that 'onion'
is ignored and has no variable bound to
it.
For objects
We can do something similar for extracting object properties into variables:
const smoothie = {fats: [ 'avocado', 'peanut butter', 'greek yogurt' ],liquids: [ 'almond milk' ],greens: [ 'spinach' ],fruits: [ 'blueberry', 'banana' ],};โconst { liquids, fruits } = smoothie;โconsole.log(liquids);console.log(fruits);
Parameter context matching
We can use these same principles to bind arguments inside a function to properties of an object supplied as an argument:
const containsSpinach = ({ greens }) => {if (greens.find(g => g === 'spinach')) {return true;} else {return false;}};โcontainsSpinach(smoothie);
We do this often with functional React components:
const IngredientList = ({ ingredients, onClick }) => (<ul className='IngredientList'>{ingredients.map(i => (<likey={i.id}onClick={() => onClick(i.id)}className='item'>{i.name}</li>))}</ul>)
Here, we use destructuring to extract the
props into variables (ingredients
and onClick) that we then use inside the
component's function body.
โ
โ
โ
React.Component ยท render() ยท componentDidMount() ยท props/state ยท dangerouslySetInnerHTML ยท React is a JavaScript library for building user interfaces. This guide targets React v15 to v16.
โReact is a JavaScript library for building user interfaces. This guide targets React v15 to v16.
render() {return <div />;}
constructor(props) {super(props);this.state = {list: props.initialList};}โ// where props aren't used in constructorโconstructor() {super();this.state = {list: []};}
componentWillMount() {// invoked once.// fires before initial 'render'}
componentDidMount() {// good for AJAX: fetch, ajax, or subscriptions.โ// invoked once (client-side only).// fires before initial 'render'}
componentWillReceiveProps(nextProps) {// invoked every time component recieves new props.// does not before initial 'render'}
shouldComponentUpdate(nextProps, nextState) {// invoked before every update (new props or state).// does not fire before initial 'render'.}
componentWillUpdate(nextProps, nextState) {// invoked immediately before update (new props or state).// does not fire before initial 'render'.โ// (see componentWillReceiveProps if you need to call setState)}
โ this.setState
componentDidUpdate(prevProps, prevState) {// invoked immediately after DOM updates// does not fire after initial 'render'}
componentWillUnmount() {// invoked immediately before a component is unmounted.}
// good for state transitionsโthis.setState((prevState, props) => {return {count: prevState.count + props.step};});
// good for static valuesโthis.setState({mykey: 'my new value'});
// fires after setState// prefer componentDidUpdateโthis.setState((prevState, props) => ({ count: prevState.count + props.step }),() => console.log(this.state.count));
// forces a re-render; AVOID if possibleโthis.forceUpdate();
displayName: "MyComponent"
class Greeting extends React.Component {render() {return <h1>Hi {this.props.name}</h1>}}โCustomButton.defaultProps = {name: 'guest'};
React.Children.map(this.props.children, (child, i) => {return child;})
React.Children.forEach(this.props.children, (child, i) => {console.log(child + ' at index: ' + i);})
React.Children.count(this.props.children);
React.Children.only(this.props.children);
React.Children.toArray(this.props.children)
// requires 'prop-types' libraryโimport { string } from "prop-types";โclass Cowboy extends React.Component {childContextTypes: {salutation: string}โgetChildContext() {return { salutation: "Howdy" };}โrender() {return React.Children.only(this.props.children);}}โconst Greeting = (props, context) =><div>{context.salutation} {props.name}.</div>โGreeting.contextTypes = {salutation: PropTypes.string}โ// <Greeting name="Michael" />// => Michael.โ// <Cowboy><Greeting name="Michael" /></Cowboy>// => Howdy Michael.
// add to the context-aware component// requires 'prop-types' libraryโcontextTypes: {color: PropTypes.string},
// add to the context provider// requires 'prop-types' libraryโchildContextTypes: {color: PropTypes.string},
// add to the context providerโgetChildContext() {return {color: "purple"};}
import React from 'react'import ReactDOM from 'react-dom'โโclass Hello extends React.Component {render () {return <div className='message-box'>Hello {this.props.name}</div>}}โโconst el = document.bodyReactDOM.render(<Hello name='John' />, el)
Use the React.js jsfiddle to start hacking. (or the unofficial jsbin)
import React, {Component} from 'react'import ReactDOM from 'react-dom'โโclass Hello extends Component {...}
<Video fullscreen={true} autoplay={false} />โโrender () {this.props.fullscreenconst { fullscreen, autoplay } = this.propsยทยทยท}
Use this.props
to access properties passed to the
component.
See: Propertiesโ
constructor(props) {super(props)this.state = { username: undefined }}โโthis.setState({ username: 'rstacruz' })โโrender () {this.state.usernameconst { username } = this.stateยทยทยท}
Use states (this.state) to manage dynamic data.
With Babel you can use proposal-class-fields and get rid of constructor
class Hello extends Component {state = { username: undefined };...}
See: Statesโ
class Info extends Component {render () {const { avatar, username } = this.propsโreturn <div><UserAvatar src={avatar} /><UserProfile username={username} /></div>}}
As of React v16.2.0, fragments can be used to return multiple children without adding extra wrapping nodes to the DOM.
import React, {Component,Fragment} from 'react'โclass Info extends Component {render () {const { avatar, username } = this.propsโreturn (<Fragment><UserAvatar src={avatar} /><UserProfile username={username} /></Fragment>)}}
Nest components to separate concerns.
See: Composing Componentsโ
<AlertBox><h1>You have pending notifications</h1></AlertBox>โโclass AlertBox extends Component {render () {return <div className='alert-box'>{this.props.children}</div>}}
Children are passed as the children
property.
Hello.defaultProps = {color: 'blue'}
See: defaultPropsโ
class Hello extends Component {constructor (props) {super(props)this.state = { visible: true }}}
Set the default state in the constructor().
And without constructor using Babel with proposal-class-fields.
class Hello extends Component {state = { visible: true }}
See: Setting the default stateโ
function MyComponent ({ name }) {return <div className='message-box'>Hello {name}</div>}
Functional components have no state. Also,
their props
are passed as the first parameter to a
function.
See: Function and Class Componentsโ
import React, {PureComponent} from 'react'โclass MessageBox extends PureComponent {ยทยทยท}
Performance-optimized version of React.Component. Doesnโt rerender if props/state hasnโt
changed.
See: Pure componentsโ
this.forceUpdate()โโthis.setState({ ... })this.setState(state => { ... })โโthis.statethis.props
These methods and properties are available
for Component
instances.
See: Component APIโ
Set initial the state on constructor(). Add DOM event handlers, timers (etc) on componentDidMount(), then remove them on componentWillUnmount().
|
Method |
Description |
|
|
Use |
|
|
Skips |
|
|
Render |
|
|
Operate on the DOM here |
Called when parents change properties and .setState(). These are not called for initial
renders.
See: Component specsโ
import React, { useState } from 'react';โfunction Example() {โconst [count, setCount] = useState(0);โreturn (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);}
Hooks are a new addition in React 16.8.
See: Hooks at a Glanceโ
function ExampleWithManyStates() {โconst [age, setAge] = useState(42);const [fruit, setFruit] = useState('banana');const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);โ}
import React, { useState, useEffect } from 'react';โfunction Example() {const [count, setCount] = useState(0);โโuseEffect(() => {โdocument.title = `You clicked ${count} times`;}, [count]);โreturn (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);}
If youโre familiar with React class
lifecycle methods, you can think of useEffect
Hook as componentDidMount, componentDidUpdate, and componentWillUnmount
combined.
By default, React runs the effects after every render โ including the first render.
Define FriendStatus
import React, { useState, useEffect } from 'react';โfunction FriendStatus(props) {const [isOnline, setIsOnline] = useState(null);โuseEffect(() => {function handleStatusChange(status) {setIsOnline(status.isOnline);}โChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);return () => {ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);};}, [props.friend.id]);โif (isOnline === null) {return 'Loading...';}return isOnline ? 'Online' : 'Offline';}
Effects may also optionally specify how to โclean upโ after them by returning a function.
Use FriendStatus
function FriendStatus(props) {const isOnline = useFriendStatus(props.friend.id);โif (isOnline === null) {return 'Loading...';}return isOnline ? 'Online' : 'Offline';}
See: Building Your Own Hooksโ
Also see: Hooks FAQโ
Basic Hooks
|
Hook |
Description |
|
|
โ |
|
|
โ |
|
|
value returned from |
Full details: Basic Hooksโ
Additional Hooks
|
Hook |
Description |
|
|
โ |
|
|
โ |
|
|
โ |
|
|
โ |
|
|
โ |
|
|
identical to |
|
|
display a label for custom hooks in React DevTools |
Full details: Additional Hooksโ
class MyComponent extends Component {render () {return <div><input ref={el => this.input = el} /></div>}โcomponentDidMount () {this.input.focus()}}
Allows access to DOM nodes.
See: Refs and the DOMโ
class MyComponent extends Component {render () {<input type="text"value={this.state.value}onChange={event => this.onChange(event)} />}โonChange (event) {this.setState({ value: event.target.value })}}
Pass functions to attributes like onChange.
See: Eventsโ
<VideoPlayer src="video.mp4" />โโclass VideoPlayer extends Component {render () {return <VideoEmbed {...this.props} />}}
Propagates src="..."
down to the sub-component.
See Transferring propsโ
React.createClass({ ... })React.isValidElement(c)โโReactDOM.render(<Component />, domnode, [callback])ReactDOM.unmountComponentAtNode(domnode)โโReactDOMServer.renderToString(<Component />)ReactDOMServer.renderToStaticMarkup(<Component />)
There are more, but these are most common.
See: React top-level APIโ
const style = { height: 10 }return <div style={style}></div>โโreturn <div style={{ margin: 0, padding: 0 }}></div>
See: Inline stylesโ
function markdownify() { return "<p>...</p>"; }<div dangerouslySetInnerHTML={{__html: markdownify()}} />
See: Dangerously set innerHTMLโ
class TodoList extends Component {render () {const { items } = this.propsโreturn <ul>{items.map(item =><TodoItem item={item} key={item.key} />)}</ul>}}
Always supply a key
property.
<Fragment>{showMyComponent? <MyComponent />: <OtherComponent />}</Fragment>
<Fragment>{showPopup && <Popup />}...</Fragment>
You can return multiple elements as arrays or fragments.
Arrays
render () {โreturn [<li key="A">First item</li>,<li key="B">Second item</li>]}
Fragments
render () {โreturn (<Fragment><li>First item</li><li>Second item</li></Fragment>)}
See: Fragments and stringsโ
render() {return 'Look ma, no spans!';}
You can return just a string.
See: Fragments and stringsโ
class MyComponent extends Component {ยทยทยทcomponentDidCatch (error, info) {this.setState({ error })}}
Catch errors via componentDidCatch. (React 16+)
See: Error handling in React 16โ
render () {return React.createPortal(this.props.children,document.getElementById('menu'))}
This renders this.props.children
into any location in the DOM.
See: Portalsโ
const el = document.getElementById('app')ReactDOM.hydrate(<App />, el)
Use ReactDOM.hydrate
instead of using ReactDOM.render
if youโre rendering over the output of
ReactDOMServer.
See: Hydrateโ
import PropTypes from 'prop-types'
See: Typechecking with PropTypesโ
|
Key |
Description |
|
|
Anything |
Basic
|
Key |
Description |
|
|
โ |
|
|
โ |
|
|
Function |
|
|
True or false |
Enum
|
Key |
Description |
|
|
Enum types |
|
|
Union |
Array
|
Key |
Description |
|
|
โ |
|
|
โ |
Object
|
Key |
Description |
|
|
โ |
|
|
Object with values of a certain type |
|
|
Instance of a class |
|
|
โ |
Elements
|
Key |
Description |
|
|
React element |
|
|
DOM node |
Required
|
Key |
Description |
|
|
Required |
MyComponent.propTypes = {email: PropTypes.string,seats: PropTypes.number,callback: PropTypes.func,isClosed: PropTypes.bool,any: PropTypes.any}
MyCo.propTypes = {name: PropTypes.string.isRequired}
MyCo.propTypes = {โelement: PropTypes.element,โโnode: PropTypes.node}
MyCo.propTypes = {direction: PropTypes.oneOf(['left', 'right'])}
MyCo.propTypes = {list: PropTypes.array,ages: PropTypes.arrayOf(PropTypes.number),user: PropTypes.object,user: PropTypes.objectOf(PropTypes.number),message: PropTypes.instanceOf(Message)}โโMyCo.propTypes = {user: PropTypes.shape({name: PropTypes.string,age: PropTypes.number})}
Use .array[Of], .object[Of], .instanceOf, .shape.
MyCo.propTypes = {customProp: (props, key, componentName) => {if (!/matchme/.test(props[key])) {return new Error('Validation failed!')}}}